package com.drg.center.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.drg.center.dao.*;
import com.drg.center.entity.*;
import com.drg.center.entity.param.MockDaysDTO;
import com.drg.center.entity.result.PatientCaseAdviceVO;
import com.drg.center.entity.result.PatientCaseDiagnosisVO;
import com.drg.center.entity.result.PatientCaseOperationVO;
import com.drg.center.entity.result.PatientCasePersonInfoVO;
import com.drg.center.mapper.PatientCaseEsMapper;
import com.github.javafaker.Faker;
import com.google.common.collect.Lists;
import com.guaike.core.entity.result.Result;
import com.guaike.core.utils.CompareUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Sets;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

/**
 * @Author: zhangxilin
 * @Date: 2024/11/27
 */
@Slf4j
@RestController
@RequestMapping("/openApi/mock")
@Api(tags = "对接his的Mock接口组")
public class DrgHisMockController {

    private static final Faker faker = new Faker(new Locale("zh_CN"));

    @Autowired
    private SysDepartDAO sysDepartDAO;
    @Autowired
    private SysDoctorDAO sysDoctorDAO;
    @Autowired
    private DictDrgDAO dictDrgDAO;
    @Autowired
    private PatientCaseEsMapper patientCaseEsMapper;
    @Autowired
    private DictDiagnosisHisDAO dictDiagnosisHisDAO;
    @Autowired
    private DictOperationDAO dictOperationDAO;
    @Autowired
    private DictProjectDAO dictProjectDAO;

    private static Map<String, Integer> totalCountMap = new ConcurrentHashMap<>();
    private static Map<String, List<SysDoctorPO>> doctorMap = new ConcurrentHashMap<>();
    private static List<SysDepartPO> departs;
    private static List<DictDrgPO> drgs;
    private static List<DictDiagnosisHisPO> diagnosis;
    private static List<DictOperationPO> operations;
    private static List<DictProjectPO> dictProjects;

    private static List<Integer> outReason = new ArrayList<>();
    private static List<Integer> outReasonInJz = Arrays.asList(1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 9);

    private static List<Integer> dealthRisk = Arrays.asList(1, 2, 3, 4);

    private static List<String> hasDeathDepartList = Arrays.asList("52.28", "52.27", "52.24", "52.20", "52.17", "52.11");

    private static void add(int count, int value) {
        for (int i = 0; i < count; i++) {
            outReason.add(value);
        }
    }


    @PostMapping("/mock")
    @ApiOperation(value = "mock数据")
    public Result<Boolean> mock(@Valid @RequestBody MockDaysDTO param) {
        totalCountMap.clear();
        initData();
        List<YearMonth> yearMonthList = getYearMonthList(param.getBeforeMonty());
        for (YearMonth yearMonth : yearMonthList) {
            mockItem(yearMonth);
        }
//        ExecutorService executor =  ThreadUtil.newExecutor(5, 10);
//        // 异步处理列表中的每个元素
//        List<CompletableFuture<Void>> futures = execAsync(yearMonthList, executor);
//        // 等待所有任务完成
//        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
//
//        // 关闭线程池
//        executor.shutdown();
        printLog();
        return Result.success().data(Boolean.TRUE).build();
    }

    private void printLog() {
        log.info("============================模拟生成数据完毕, 明细如下================================================");
        Integer total = 0;
        for (Map.Entry<String, Integer> entry : totalCountMap.entrySet()) {
            log.info("月份： {}， 模拟生成数据量: {}", entry.getKey(), entry.getValue());
            total = total + entry.getValue();
        }

        log.info("=============================================================================");
        log.info(">>>>>>>>>>>>>>>>>>>模拟总病历: {}例", total);
    }

    // 使用线程池异步处理列表中的每个元素
    public List<CompletableFuture<Void>> execAsync(List<YearMonth> items, Executor executor) {
        return items.stream()
                .map(item -> CompletableFuture.runAsync(() -> mockItem(item), executor))
                .collect(Collectors.toList());
    }

    private static List<YearMonth> getYearMonthList(int beforeMonth) {
        List<YearMonth> list = Lists.newArrayList();
        YearMonth currentYearMonth = YearMonth.now();
        for (int i = beforeMonth; i >= 0; i--) {
            YearMonth month = currentYearMonth.minusMonths(i);
            list.add(month);
        }
        return list;
    }

    private void initData() {
        //科室
        departs = getDepts();

        //医生
        List<SysDoctorPO> doctorPOList = sysDoctorDAO.findAll();
        doctorMap = doctorPOList.stream().collect(Collectors.groupingBy(SysDoctorPO::getDepartCode));

        //drg
        List<DictDrgPO> drgPOList = dictDrgDAO.findAll();
        drgs = drgPOList;

        //诊断
        List<DictDiagnosisHisPO> diagnosisHisPOS = dictDiagnosisHisDAO.findAll();
        diagnosis = diagnosisHisPOS;


        //手术
        List<DictOperationPO> poList = dictOperationDAO.findAll();
        operations = poList;

        //医嘱项目
        List<DictProjectPO> pos = dictProjectDAO.findAll();
        dictProjects = pos;

        //初始化outReason
        add(180, 1);
        add(5, 2);
        add(5, 3);
        add(1, 4);
        add(9, 9);
        log.info("加载outReason完成: {}", JSONObject.toJSONString(outReason));
    }

    private void mockItem(YearMonth yearMonth) {
        log.info(">>>>>>>>>>>>>--month: {}", yearMonth);
        List<PatientCaseEsPO> list = new ArrayList<>();
        BigDecimal rate = getDayRate(yearMonth);
        for (SysDepartPO departPO : departs) {
            Integer index = getCount(rate);
            for (int i = 0; i <= index; i++) {
                list.add(generatePatientCasePO(yearMonth, departPO));
            }
        }
        totalCountMap.put(yearMonth.toString(), list.size());
        log.info(">>>>>>>>>>>>>>>> month: {}, 数据量: {}", yearMonth, list.size());
        patientCaseEsMapper.saveAll(list);
        log.info("---------------------------");
    }

    private static Integer getCount(BigDecimal rate) {
        Integer count = RandomUtil.randomInt(80, 300);
        BigDecimal countBg = BigDecimal.valueOf(count);
        BigDecimal result = rate.multiply(countBg);
        return result.setScale(0, RoundingMode.HALF_UP).intValue();
    }

    private static BigDecimal getDayRate(YearMonth yearMonth) {
        LocalDate endOfMonth = yearMonth.atEndOfMonth();
        LocalDate now = LocalDate.now();
        if (endOfMonth.isBefore(now)) {
            return BigDecimal.ONE;
        }
        int day = now.getDayOfMonth();
        BigDecimal dayBig = BigDecimal.valueOf(day);
        BigDecimal totalBig = new BigDecimal("30");
        return dayBig.divide(totalBig, 2, RoundingMode.HALF_UP);
    }


    private PatientCaseEsPO generatePatientCasePO(YearMonth yearMonth, SysDepartPO departPO) {
        PatientCaseEsPO record = new PatientCaseEsPO();
        record.setCaseCode(faker.number().digits(10));
        record.setDepartCode(departPO.getDepartCode());
        record.setDepartName(departPO.getDepartName());
        record.setInHospitalDate(getRandomDayOfMonth(yearMonth));
        record.setInpatientCode(faker.number().digits(10));
        record.setBedCode(faker.number().digits(4));

        setDoctor(departPO.getDepartCode(), record);

        if (isHit(0.97)) {
            int index = RandomUtil.randomInt(0, drgs.size());
            DictDrgPO drgPO = drgs.get(index);
            record.setDrgCode(drgPO.getDrgCode());
            record.setDrgName(drgPO.getDrgName());
            record.setWeightInDrg(drgPO.getDrgWeight());
            record.setDrgYbCode(drgPO.getDrgCode());
            record.setDrgYbName(drgPO.getDrgName());
            record.setWeightYbInDrg(drgPO.getDrgWeight());
        } else {
            record.setDrgCode("0000");
            record.setDrgName("0000组");
            record.setWeightInDrg(new BigDecimal("0.08"));
        }
        record.setMagnification(RandomUtil.randomInt(1, 3));
        record.setCasePoints(randomRate(0, 1));
        record.setRw(randomRate(0, 10));
        record.setBasisPoints(randomRate(0, 10));
        record.setMagnificationYb(RandomUtil.randomInt(1, 3));
        record.setCaseYbPoints(randomRate(0, 1));
        record.setRwYb(randomRate(0, 10));
        record.setBasisYbPoints(randomRate(0, 10));
        record.setSettleMoney(BigDecimal.valueOf(faker.number().randomDouble(2, 1000, 10000)));
        record.setFundCost(BigDecimal.valueOf(faker.number().randomDouble(2, 1000, 10000)));
        if (isHit(0.1)) {
            record.setIsWarn(Boolean.TRUE);
        }

        //住院天数
        int hosInDays = RandomUtil.randomInt(3, 40);
        if (isConfimOut(record.getInHospitalDate(), hosInDays)) {
            record.setHasOut(true);
            record.setOutDepartCode(departPO.getDepartCode());
            record.setOutDepartName(departPO.getDepartName());
            record.setOutHospitalDate(record.getInHospitalDate().plusDays(hosInDays));
            record.setTotalCost(BigDecimal.valueOf(faker.number().randomDouble(2, 1000, 10000)));
            record.setExpectCost(BigDecimal.valueOf(faker.number().randomDouble(2, 1000, 10000)));
            record.setSettleDate(record.getOutHospitalDate());
            record.setTotalSettleCost(BigDecimal.valueOf(faker.number().randomDouble(2, 1000, 10000)));
            record.setProfit(BigDecimal.ZERO);
            record.setExpectProfit(BigDecimal.ZERO);
            if (StringUtils.isNotBlank(record.getDrgCode())) {
                record.setProfit(BigDecimal.valueOf(faker.number().randomDouble(2, -5000, 6000)));
                record.setExpectProfit(BigDecimal.valueOf(faker.number().randomDouble(2, -4000, 5000)));
            }

            if (record.getProfit().compareTo(new BigDecimal(0)) < 0) {
                record.setLossReason(faker.options().option("医保基金结算清单填报不准确", "住院医疗总费用超过支付标准", "医院管理问题", "DRG/DIP分组方案差异", "患者病情特殊", "主诊断填写不规范"));
                record.setOverEffect(faker.options().option("经济压力增加", "运营效率下降", "医疗资源配置不均"));
            }

            if (isHit(0.3)) {
                record.setOverExpectCost(BigDecimal.valueOf(faker.number().randomDouble(2, 10, 1000)));
            }
            record.setInpatientDays(hosInDays);

            if (hasDeathDepartList.contains(record.getDepartCode())) {
                Integer outReasonIndex = RandomUtil.randomInt(0, outReasonInJz.size());
                String outType = outReasonInJz.get(outReasonIndex) + "";
                if (CompareUtil.isEqual(outType, "4")) {
                    outReasonIndex = RandomUtil.randomInt(0, outReasonInJz.size());
                    outType = outReasonInJz.get(outReasonIndex) + "";
                }
                record.setOutType(outType);
            } else {
                Integer outReasonIndex = RandomUtil.randomInt(0, outReason.size());
                String outType = outReason.get(outReasonIndex) + "";
                if (CompareUtil.isEqual(outType, "4")) {
                    outReasonIndex = RandomUtil.randomInt(0, outReason.size());
                    outType = outReason.get(outReasonIndex) + "";
                }
                record.setOutType(outType);
            }

            if (CompareUtil.isEqual(record.getOutType(), "4")) {
                record.setDealthRisk(dealthRisk.get(RandomUtil.randomInt(0, dealthRisk.size())));
            }

            if (hosInDays >= 30) {
                record.setIsOverlengthIn(true);
            }
            record.setIsLowStandardIn(isHit(0.3));
        }

        if (isHit(0.2)) {
            record.setControlStandard(BigDecimal.valueOf(faker.number().randomDouble(2, 10, 1000)));
            record.setControlStandardDoctor(BigDecimal.valueOf(faker.number().randomDouble(2, 10, 1000)));
            record.setPrePayTotal(BigDecimal.valueOf(faker.number().randomDouble(2, 10, 1000)));
            record.setPrePayTotalDoctor(BigDecimal.valueOf(faker.number().randomDouble(2, 10, 1000)));
            record.setCaseBasedPayment(BigDecimal.valueOf(faker.number().randomDouble(2, 10, 1000)));
            record.setCaseBasedPaymentDoctor(BigDecimal.valueOf(faker.number().randomDouble(2, 10, 1000)));
        }

        // 手术
        record.setHasOperation(false);
        if (isHit(0.6)) {
            record.setHasOperation(true);
        }


        record.setIsNormalCase(true);
        if (isHit(0.3)) {
            record.setIsNormalCase(false);
            record.setIsDiagnosisProblem(isHit(0.6));
            record.setIsOperationProblem(record.getHasOperation() && isHit(0.3));
            record.setIsTraditionalProblem(isHit(0.3));
        }

        record.setVisitDate(record.getInHospitalDate());
        int index2 = RandomUtil.randomInt(0, departs.size());
        SysDepartPO sysDepartPO = departs.get(index2);
        record.setSpecialDepartCode(sysDepartPO.getDepartCode());
        record.setSpecialDepartName(sysDepartPO.getDepartName());
        record.setMedicineCost(BigDecimal.valueOf(faker.number().randomDouble(2, 100, 1000)));
        record.setConsumablesCost(BigDecimal.valueOf(faker.number().randomDouble(2, 100, 1000)));
        record.setInHospitalCost(BigDecimal.valueOf(faker.number().randomDouble(2, 1000, 10000)));
        record.setOperationCost(BigDecimal.valueOf(faker.number().randomDouble(2, 1000, 10000)));
        record.setAnesthesiaCost(BigDecimal.valueOf(faker.number().randomDouble(2, 100, 1000)));
        record.setInspectCost(BigDecimal.valueOf(faker.number().randomDouble(2, 100, 1000)));
        record.setTestCost(BigDecimal.valueOf(faker.number().randomDouble(2, 100, 1000)));
        record.setOtherCost(BigDecimal.valueOf(faker.number().randomDouble(2, 100, 1000)));
        record.setTreatType(faker.options().option("1", "2"));
        record.setTreatClass(faker.options().option("1", "2.1", "2.2", "3"));
        record.setIntoChannel(faker.options().option("1", "2", "3", "9"));
        record.setVentilatorUseTime(faker.number().digits(2) + "小时");
        record.setBeforeComaTime(faker.number().digits(2) + "小时");
        record.setAfterComaTime(faker.number().digits(2) + "小时");
        record.setTransBloodVariety(faker.lorem().word());
        record.setTransBloodQuantity(faker.number().digits(3) + "毫升");
        record.setTransBloodUnit("毫升");
        record.setPremiumCareDays(faker.number().numberBetween(1, 10));
        record.setFirstCareDays(faker.number().numberBetween(1, 10));
        record.setSecondCareDays(faker.number().numberBetween(1, 10));
        record.setThirdCareDays(faker.number().numberBetween(1, 10));
        int index = RandomUtil.randomInt(0, diagnosis.size());
        DictDiagnosisHisPO chinaDiagnosis = diagnosis.get(index);
        record.setChinaDiagnosis(chinaDiagnosis.getDiagnosisName());
        record.setChinaDiseaseCode(chinaDiagnosis.getDiagnosisCode());
        int index1 = RandomUtil.randomInt(0, diagnosis.size());
        DictDiagnosisHisPO westDiagnosis = diagnosis.get(index1);
        record.setWesternDiagnosis(westDiagnosis.getDiagnosisName());
        record.setWesternDiseaseCode(westDiagnosis.getDiagnosisCode());
        record.setPayType(faker.options().option("1", "2", "3", "4", "5", "6", "9"));

        record.setPersonInfoVO(generatePatientInfo());
        record.setOperationVOS(generateOperationList(record));
        record.setDiagnosisVOS(generateDiagnosisList(record.getDoctorCode(), record.getDoctorName()));

        setAdvice(record);
        return record;
    }

    private List<PatientCaseDiagnosisVO> generateDiagnosisList(String doctorCode, String doctorName) {
        List<PatientCaseDiagnosisVO> list = Lists.newArrayList();
        int count = RandomUtil.randomInt(0, 4);
        int mainIndex = count == 0 ? 0 : RandomUtil.randomInt(0, count);
        for (int i = 0; i <= count; i++) {
            PatientCaseDiagnosisVO diagnosisVO = new PatientCaseDiagnosisVO();
            diagnosisVO.setDiagnosisType(faker.options().option(1, 2));
            int idx = RandomUtil.randomInt(0, diagnosis.size());
            DictDiagnosisHisPO hisPO = diagnosis.get(idx);
            diagnosisVO.setDiagnosisCode(hisPO.getHisDiagnosisCode());
            diagnosisVO.setDiagnosisName(hisPO.getHisDiagnosisName());
            diagnosisVO.setMedicareDiagnosisCode(hisPO.getDiagnosisCode());
            diagnosisVO.setDiagnosisCode(hisPO.getDiagnosisName());
            diagnosisVO.setDoctorCode(doctorCode);
            diagnosisVO.setDoctorName(doctorName);
            diagnosisVO.setIsMain(mainIndex == i);
            diagnosisVO.setIsTreat(faker.bool().bool());
            diagnosisVO.setInHospitalIllness(faker.options().option("有", "临床未确定", "情况不明", "无"));
            list.add(diagnosisVO);
        }
        return list;
    }

    private List<PatientCaseOperationVO> generateOperationList(PatientCaseEsPO record) {
        List<PatientCaseOperationVO> list = Lists.newArrayList();
        int count = RandomUtil.randomInt(0, 4);
        int mainIndex = count == 0 ? 0 : RandomUtil.randomInt(0, count);
        for (int i = 0; i <= count; i++) {
            PatientCaseOperationVO operationVO = new PatientCaseOperationVO();
            operationVO.setOperationLevel(faker.options().option("1", "2", "3", "4"));

            operationVO.setIsMiniOperation(Boolean.FALSE);
            if (CompareUtil.isEqual(operationVO.getOperationLevel(), "4") && isHit(0.2)) {
                operationVO.setIsMiniOperation(Boolean.TRUE);
            }
            int idx1 = RandomUtil.randomInt(0, operations.size());
            DictOperationPO operationPO = operations.get(idx1);
            operationVO.setOperationCode(operationPO.getOperationCode()); // 假设手术操作编码为6位数字
            operationVO.setOperationName(operationPO.getOperationName()); // 注意：Faker的medical.procedure可能不是中文，你可能需要自定义
            operationVO.setMedicareOperationCode(operationPO.getMedicareOperationCode()); // 假设医保手术操作编码为8位数字
            operationVO.setMedicareOperationName(operationPO.getMedicareOperationName()); // 同上
            operationVO.setIsMain(mainIndex == i);
            operationVO.setIsUpload(faker.bool().bool());
            LocalDateTime endDate = record.getOutHospitalDate() == null ? LocalDateTime.now() : record.getOutHospitalDate();
            LocalDateTime operationDate = randomDate(record.getInHospitalDate(), endDate);
            operationVO.setOperationDate(operationDate);

            List<SysDoctorPO> doctorPOList = doctorMap.get(record.getDepartCode());
            if (!CollectionUtils.isEmpty(doctorPOList)) {
                int idx = RandomUtil.randomInt(0, doctorPOList.size());
                SysDoctorPO po = doctorPOList.get(idx);
                operationVO.setOperationDoctorCode(po.getDoctorCode());
                operationVO.setOperationDoctorName(po.getDoctorName());
            }


            operationVO.setAnesthesiaType(faker.options().option("全身麻醉", "局部麻醉", "表面麻醉", "椎管内麻醉"));
            operationVO.setAnesthesiaDoctorCode(faker.number().digits(5)); // 假设医生编码为5位数字
            operationVO.setAnesthesiaDoctorName(faker.name().fullName());

            // 麻醉时间比手术时间早30分钟到2小时之间随机生成
            LocalDateTime anesthesiaDate = operationDate.minusMinutes(faker.number().numberBetween(30, 120));
            operationVO.setAnesthesiaDate(anesthesiaDate);
            list.add(operationVO);
        }
        return list;
    }

    private boolean isConfimOut(LocalDateTime hosInTime, int hosInDays) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime hosOutDate = hosInTime.plusDays(hosInDays);
        if (hosOutDate.isBefore(now)) {
            return true;
        }
        return false;
    }

    private void setDoctor(String deptCode, PatientCaseEsPO record) {
        List<SysDoctorPO> poList = doctorMap.get(deptCode);
        if (CollectionUtils.isEmpty(poList)) {
            return;
        }
        int i = RandomUtil.randomInt(0, poList.size());
        SysDoctorPO po = poList.get(i);
        record.setDoctorCode(po.getDoctorCode());
        record.setDoctorName(po.getDoctorName());
        record.setDoctorGroupCode(po.getDoctorGroupCode());
        record.setDoctorGroupName(po.getDoctorGroupName());
    }

    private void setAdvice(PatientCaseEsPO record) {
        int i = RandomUtil.randomInt(0, dictProjects.size());
        DictProjectPO po = dictProjects.get(i);
        PatientCaseAdviceVO vo = new PatientCaseAdviceVO();
        vo.setAdviceType(faker.options().option(0, 1));
        vo.setAdviceKind(0);
        vo.setAdviceContentCode(po.getProjectCode());
        vo.setAdviceContent(po.getProjectName());
        vo.setDepartCode(record.getDepartCode());
        vo.setDepartName(record.getDepartName());
        vo.setDoctorCode(record.getDoctorCode());
        vo.setDoctorName(record.getDoctorName());
        vo.setIsMain(po.getIsMain());
        int days = RandomUtil.randomInt(3, 40);
        vo.setEndTime(LocalDateTime.now().minusDays(days));
        vo.setStartTime(vo.getEndTime().minusDays(days));
        record.setAdviceVOS(Collections.singletonList(vo));
    }


    private List<SysDepartPO> getDepts() {
        List<SysDepartPO> poList = sysDepartDAO.findAll();
        Set<String> pcodeSet = poList.stream().filter(item -> StringUtils.isNotBlank(item.getParentCode())).map(SysDepartPO::getParentCode).collect(Collectors.toSet());
        return poList.stream().filter(item -> !pcodeSet.contains(item.getDepartCode())).collect(Collectors.toList());
    }

    private static LocalDateTime randomDate(LocalDateTime fromDate, LocalDateTime toDate) {
        try {
            Date date = faker.date().between(convertToLocalDate(fromDate), convertToLocalDate(toDate));
            return DateUtil.toLocalDateTime(date);
        } catch (IllegalArgumentException e) {
            return fromDate.plusDays(1);
        }
    }

    private static BigDecimal randomRate(double min, double max) {
        return BigDecimal.valueOf(RandomUtil.randomDouble(min, max, 2, RoundingMode.HALF_UP));
    }

    public static void main(String[] args) {


        System.out.println("Simulated ID Number: " + generateIdCardNum());
    }

    private static String generateIdCardNum() {
        Random random = new Random();

        // 地址码 - 这里简单随机生成6位数字作为示例
        String addressCode = String.format("%06d", faker.number().numberBetween(100000, 999999));

        // 出生日期 - 使用Faker生成合理的出生日期，并格式化为"yyyyMMdd"
        LocalDate birthDate = LocalDate.now().minus(random.nextInt((int) ChronoUnit.YEARS.between(LocalDate.of(1900, 1, 1), LocalDate.now())), ChronoUnit.YEARS);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        String birthDateStr = birthDate.format(formatter);

        // 顺序码 - 随机选择
        int sequenceCode = random.nextInt(999); // 生成0-999之间的随机数
        String sequenceCodeStr = String.format("%03d", sequenceCode);

        // 拼接成18位身份证号码，注意这里没有真实的校验码
        // 'X' 是占位符，实际应用中应该计算真实的校验码
        return addressCode + birthDateStr + sequenceCodeStr + "X";
    }

    public static LocalDateTime getRandomDayOfMonth(YearMonth yearMonth) {

        // 获取该月的第一天和最后一天
        LocalDate startOfMonth = yearMonth.atDay(1);
        LocalDate endOfMonth = yearMonth.atEndOfMonth();
        if (endOfMonth.isAfter(LocalDate.now())) {
            endOfMonth = LocalDate.now();
        }

        // 随机选择一个月中的某一天
        long randomDay = ThreadLocalRandom.current().nextLong(startOfMonth.toEpochDay(), endOfMonth.toEpochDay() + 1);
        LocalDate randomDate = LocalDate.ofEpochDay(randomDay);

        // 随机选择一天中的某一时刻（可选）
        LocalTime randomTime = LocalTime.of(ThreadLocalRandom.current().nextInt(0, 24),
                ThreadLocalRandom.current().nextInt(0, 60),
                ThreadLocalRandom.current().nextInt(0, 60));

        // 结合日期和时间得到最终的LocalDateTime对象
        return LocalDateTime.of(randomDate, randomTime);
    }

    /**
     * 根据提供的命中概率返回是否命中的结果
     *
     * @param probability
     * @return
     */
    public static boolean isHit(double probability) {
        if (probability < 0 || probability > 1) {
            throw new IllegalArgumentException("概率必须在0和1之间");
        }

        Random random = new Random();
        // 生成一个0到1之间的随机数
        double randomValue = random.nextDouble();
        // 如果随机数小于提供的概率，则认为是命中
        return randomValue < probability;
    }

    public static Date convertToLocalDate(LocalDateTime localDateTime) {
        // 将 LocalDateTime 转换为 ZonedDateTime
        ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());

        // 将 ZonedDateTime 转换为 Instant
        Instant instant = zonedDateTime.toInstant();

        // 将 Instant 转换为 Date
        return Date.from(instant);
    }


    public static PatientCasePersonInfoVO generatePatientInfo() {
        PatientCasePersonInfoVO patientInfo = new PatientCasePersonInfoVO();

        patientInfo.setPatientName(faker.name().fullName());
        patientInfo.setPatientSex(faker.options().option("1", "2"));
        patientInfo.setPatientAge(faker.number().numberBetween(0, 100));
        patientInfo.setAgeDay(faker.number().numberBetween(0, 365));
        patientInfo.setCardType(faker.options().option("身份证", "护照", "军官证"));
        patientInfo.setIdCard(generateIdCardNum());
        patientInfo.setMedicareType(faker.options().option("城镇职工", "城乡居民", "新型农村合作医疗"));
        patientInfo.setMedicareCode(faker.code().asin());
        patientInfo.setCoordinationArea(faker.address().city());
        patientInfo.setBornDate(generateRandomDateOfBirth().toString());
        patientInfo.setNationality(faker.nation().nationality());
        patientInfo.setNation(faker.nation().nationality());
        patientInfo.setCareer(faker.job().title());
        patientInfo.setProvince(faker.address().state());
        patientInfo.setCity(faker.address().city());
        patientInfo.setRegion(faker.address().cityName());
        patientInfo.setAddress(faker.address().fullAddress());
        patientInfo.setWorkCompany(faker.company().name());
        patientInfo.setWorkAddress(faker.address().fullAddress());
        patientInfo.setWorkPhone(faker.phoneNumber().cellPhone());
        patientInfo.setPostCode(faker.address().zipCode());
        patientInfo.setContactName(faker.name().fullName());
        patientInfo.setRelationship(faker.options().option("配偶", "父母", "子女", "其他"));
        patientInfo.setContactProvince(faker.address().state());
        patientInfo.setContactCity(faker.address().city());
        patientInfo.setContactRegion(faker.address().cityName());
        patientInfo.setContactAddress(faker.address().fullAddress());
        patientInfo.setContactPhone(faker.phoneNumber().cellPhone());
        patientInfo.setSpecialPersonType(faker.options().option("普通患者", "重点人群", "特殊人群"));

        // 根据患者年龄生成新生儿数据
        if (patientInfo.getPatientAge() <= 1 && patientInfo.getAgeDay() <= 365) {
            patientInfo.setNewbornType(faker.options().option("足月产", "早产", "过期产"));
            patientInfo.setNewbornBornWeight(faker.number().numberBetween(2000, 5000));
            patientInfo.setNewbornWeight(faker.number().numberBetween(2000, 5000));
        } else {
            patientInfo.setNewbornType(null);
            patientInfo.setNewbornBornWeight(null);
            patientInfo.setNewbornWeight(null);
        }

        return patientInfo;
    }

    private static LocalDate generateRandomDateOfBirth() {
        int year = faker.number().numberBetween(1920, 2020);
        int month = faker.number().numberBetween(1, 12);
        int day = faker.number().numberBetween(1, 28); // 为了避免日期越界，这里取1到28
        return LocalDate.of(year, month, day);
    }

}
